12. Functions

Note

The below information is extensively based in information taken from the PowerShell® Notes for Professionals book. I plan to extend this information based on my day to day usage of the language.

A function is basically a named block of code. When you call the function name, the script block within that function runs. It is a list of PowerShell statements that has a name that you assign. When you run a function, you type the function name. It is a method of saving time when tackling repetitive tasks. PowerShell formats in three parts: the keyword 'Function', followed by a Name, finally, the payload containing the script block, which is enclosed by curly/parenthesis style bracket.

12.1: Basic Parameters

A function can be defined with parameters using the param block:

1
2
3
4
5
6
7
8
9
function Write-Greeting {
  param(
    [Parameter(Mandatory,Position= 0 )]
    [String]$name,
    [Parameter(Mandatory,Position= 1 )]
    [Int]$age
  )
  "Hello $name, you are $age years old."
}

Or using the simple function syntax:

1
2
3
function Write-Greeting ($name, $age) {
  "Hello $name, you are $age years old."
}

Note: Casting parameters is not required in either type of parameter definition.

Simple function syntax (SFS) has very limited capabilities in comparison to the param block.

Though you can define parameters to be exposed within the function, you cannot specify Parameter Attributes, utilize Parameter Validation, include [CmdletBinding()], with SFS (and this is a non-exhaustive list).

Functions can be invoked with ordered or named parameters.

The order of the parameters on the invocation is matched to the order of the declaration in the function header (by default), or can be specified using the Position Parameter Attribute (as shown in the advanced function example, above).

1
$greeting = Write-Greeting "Jim" 82

Alternatively, this function can be invoked with named parameters

1
$greeting = Write-Greeting -name "Bob" - age 82

12.2: Advanced Function

This is a copy of the advanced function snippet from the Powershell ISE. Basically this is a template for many of the things you can use with advanced functions in Powershell. Key points to note:

1
2
3
get-help integration - the beginning of the function contains a comment block that is set up to be read by the
get-help cmdlet. The function block may be located at the end, if desired.
cmdletbinding - function will behave like a cmdlet
1
2
parameters
parameter sets
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function Verb-Noun
{
  [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
      SupportsShouldProcess=$true,
      PositionalBinding=$false,
      HelpUri = 'http://www.microsoft.com/',
  ConfirmImpact='Medium')]
  [Alias()]
  [OutputType([String])]
  Param
  (
    # Param1 help description
    [Parameter(Mandatory=$true,
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true,
        ValueFromRemainingArguments=$false,
        Position=0,
    ParameterSetName='Parameter Set 1')]
    [ValidateNotNull()]
    [ValidateNotNullOrEmpty()]
    [ValidateCount(0,5)]
    [ValidateSet("sun", "moon", "earth")]
    [Alias("p1")]
    $Param1,
    # Param2 help description
    [Parameter(ParameterSetName='Parameter Set 1')]
    [AllowNull()]
    [AllowEmptyCollection()]
    [AllowEmptyString()]
    [ValidateScript({$true})]
    [ValidateRange(0,5)]
    [int]
    $Param2,
    # Param3 help description
    [Parameter(ParameterSetName='Another Parameter Set')]GoalKicker.com - PowerShell Notes for Professionals 41
    [ValidatePattern("[a-z]*")]
    [ValidateLength(0,15)]
    [String]
    $Param3
  )
  Begin
  {}
  Process
  {
    if ($pscmdlet.ShouldProcess("Target", "Operation"))
    {}
  }
  End
  {}
}

12.3: Mandatory Parameters

Parameters to a function can be marked as mandatory

1
2
3
4
5
6
7
function Get-Greeting{
  param
  (
    [Parameter(Mandatory=$true)]$name
  )
  "Hello World $name"
}

If the function is invoked without a value, the command line will prompt for the value:

1
$greeting = Get-Greeting
1
2
3
cmdlet Get-Greeting at command pipeline position 1
Supply values for the following parameters:
name:

12.4: Parameter Validation

There are a variety of ways to validate parameter entry, in PowerShell. Instead of writing code within functions or scripts to validate parameter values, these ParameterAttributes will throw if invalid values are passed.

ValidateSet

Sometimes we need to restrict the possible values that a parameter can accept. Say we want to allow only red, green and blue for the $Color parameter in a script or function.

We can use the ValidateSet parameter attribute to restrict this. It has the additional benefit of allowing tab completion when setting this argument (in some environments).

1
2
3
4
param(
  [ValidateSet('red','green','blue',IgnoreCase)]
  [string]$Color
)

You can also specify IgnoreCase to disable case sensitivity.

ValidateRange

This method of parameter validation takes a min and max Int32 value, and requires the parameter to be within that

range.

1
2
3
4
param(
  [ValidateRange( 0 , 120 )]
  [Int]$Age
)

ValidatePattern

This method of parameter validation accepts parameters that match the regex pattern specified.

1
2
3
4
param(
  [ValidatePattern("\w{4-6}\d{2}")]
  [string]$UserName
)

ValidateLength

This method of parameter validation tests the length of the passed string.

1
2
3
4
param(
  [ValidateLength( 0 , 15 )]
  [String]$PhoneNumber
)

ValidateCount

This method of parameter validation tests the amount of arguments passed in, for example, an array of strings.

1
2
3
4
param(
  [ValidateCount( 1 , 5 )]
  [String[]]$ComputerName
)

ValidateScript

Finally, the ValidateScript method is extraordinarily flexible, taking a scriptblock and evaluating it using $_ to represent the passed argument. It then passes the argument if the result is $true (including any output as valid).

This can be used to test that a file exists:

1
2
3
4
param(
  [ValidateScript({ Test-Path $_})]
  [IO.FileInfo]$Path
)

To check that a user exists in AD:

1
2
3
4
param(
  [ValidateScript({Get-ADUser $_})]
  [String]$UserName
)

And pretty much anything else you can write (as it's not restricted to oneliners):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
param(
  [ValidateScript({
        $AnHourAgo = ( Get-Date ).AddHours(- 1 )
        if ($_ -lt $AnHourAgo.AddMinutes( 5 ) -and $_ -gt $AnHourAgo.AddMinutes(- 5 )) {
          $true
        } else {
          throw "That's not within five minutes. Try again."
        }
  })]
  [String]$TimeAboutAnHourAgo
)

12.5: Simple Function with No Parameters

This is an example of a function which returns a string. In the example, the function is called in a statement assigning a value to a variable. The value in this case is the return value of the function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function Get-Greeting{
  "Hello World"
}

# Invoking the function
$greeting = Get-Greeting

# demonstrate output
$greeting
Get-Greeting

function declares the following code to be a function.

Get-Greeting is the name of the function. Any time that function needs to be used in the script, the function can be called by means of invoking it by name.

{ ... } is the script block that is executed by the function.

If the above code is executed in the ISE, the results would be something like:

1
2
Hello World
Hello World